package com.yqh;

import com.yqh.discovery.Registry;
import com.yqh.discovery.RegistryConfig;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;

/**
 * @author 阳秋豪
 * @createTime 2024/2/28
 */
@Slf4j
public class ConsumerConfig<T> {
    private Class<T> interfaceConsumer;
    private Registry registry;


    /**
     * 代理设计模式，生成一个 api 接口的代理对象
     *
     * @return
     */
    public T get() {
        // 此处一定是使用动态代理完成了一些工作
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Class[] classes = new Class[]{interfaceConsumer};
        // 使用动态代理生成代理对象
        Object helloProxy = Proxy.newProxyInstance(classLoader, classes, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 我们调用 sayHello 方法，事实上会走进这段代码
                // 我们已经知道 method(具体的方法),args(参数列表)
                System.out.println("hello proxy");
                log.info("method -- {}", method.getName());
                log.info("args -- {}", args);
                //1、发现服务，从注册中心，寻找一个可用的服务
                // 传入服务的名字,返回一个 ip + 端口
                InetSocketAddress address = registry.lookup(interfaceConsumer.getName());
                if (log.isDebugEnabled()) {
                    log.debug("服务调用方发现了服务【{}】的可用主机【{}】", interfaceConsumer.getName(), address);
                }
                //2、使用 netty 连接服务器，发送调用的服务名称 + 方法名字 + 参数列表，得到结果
                // 定义线程池，EventLoopGroup
                NioEventLoopGroup group = new NioEventLoopGroup();
                // 启动一个客户端需要一个辅助类，bootstrap
                try {
                    Bootstrap bootstrap = new Bootstrap();
                    bootstrap = bootstrap
                            .group(group)
                            .remoteAddress(address)
                            .channel(NioSocketChannel.class)
                            .handler(new ChannelInitializer<SocketChannel>() {
                                @Override
                                protected void initChannel(SocketChannel ch) throws Exception {
                                    ch.pipeline().addLast(null);
                                }
                            });
                    // 尝试连接服务器
                    ChannelFuture channelFuture = bootstrap.connect().sync();
                    // 获取 channel，并写出数据
                    channelFuture.channel().writeAndFlush(Unpooled.copiedBuffer("hello netty".getBytes(StandardCharsets.UTF_8)));
                    // 阻塞线程，等待接受消息
                    channelFuture.channel().closeFuture().sync();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    group.shutdownGracefully().sync();
                }
                return null;
            }
        });
        return (T) helloProxy;
    }

    public Class<T> getInterfaceConsumer() {
        return interfaceConsumer;
    }

    public void setInterfaceConsumer(Class<T> interfaceConsumer) {
        this.interfaceConsumer = interfaceConsumer;
    }

    public Registry getRegistry() {
        return registry;
    }

    public void setRegistry(Registry registry) {
        this.registry = registry;
    }
}
